# -- coding:utf-8 --
"""
摸高界面主程序
延时清除线程
注释中的“事件”和“信号”可以理解为一个意义
"""

import sys
import signal
import time

from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QLabel
from PyQt4.QtCore import Qt

from ScreenPoint import ScreenPoint, PointThread
from Ultrasonic import ultralsonic
from RFIDCard import RFIDRead
from SQLWrite import SQLWrite
from Laser import laser
from Bluetooth import bluetooth
from Screw import screw

class ClearThread(QtCore.QThread):
    """
    延时清除线程
    每秒计数一次，计数满5秒则超时，当超时时向主程序发出数据清除事件
    可在主程序中将self.num变量置0重新计数
    """

    ClearPoint = QtCore.pyqtSignal()    # 清屏信号

    def __init__(self, parent=None):
        super(ClearThread, self).__init__(parent)
        self.num = 0

    def run(self):
        """
        重写run函数，当主程序调用线程的start方法时该方法自动执行
        """
        while True:
            time.sleep(1)
            self.num += 1
            if self.num >= 5:
                self.ClearPoint.emit()    # 发出清除事件

class ShowRuler(QtGui.QWidget):
    def __init__(self, StartDistance, mmHeight, pixHeight, parent = None):
        super(ShowRuler, self).__init__(parent)
        self.StartDistance = StartDistance
        self.mmHeight = mmHeight
        self.pixHeight = pixHeight
        self.resize(80, 1920)
        self.LabelSet()

    def DrawRuler(self, qp):
        for i in range(1, self.mmHeight+1):
            pixy = self.pixHeight - i * 1.0 / self.mmHeight * self.pixHeight
            self.DrawLine(self.StartDistance + i, pixy, qp)

    def DrawLine(self, mmy, pixy, qp):
        if mmy % 10 == 0:
            qp.setPen(QtGui.QPen(Qt.black, 2, Qt.SolidLine))
            qp.drawLine(0, pixy, 80, pixy)
        else:
            qp.setPen(QtGui.QPen(Qt.black, 1, Qt.SolidLine))
            qp.drawLine(40, pixy, 80, pixy)

    def LabelSet(self):
        # mmLabel = QLabel(self)
        # mmLabel.resize(65, 40)
        # mmLabel.move(0, 80)
        # mmLabel.setText(u"卡号:")
        for i in range(1, self.mmHeight+1):
            mmy = self.StartDistance + i
            if mmy % 10 == 0:
                pixy = self.pixHeight - i * 1.0 / self.mmHeight * self.pixHeight
                mmText = QLabel(self)
                mmText.setObjectName('mmText')
                mmText.resize(40, 15)
                mmText.move(0, pixy - 15)
                mmText.setText(str(mmy))

    def paintEvent(self, e):
        qp = QtGui.QPainter()
        qp.begin(self)
        self.DrawRuler(qp)
        qp.end()


class Screen(QtGui.QMainWindow):
    """
    PyQt主窗口类，继承于QtGui.QMainWindow类
    该类即为程序主界面，所有显示与子线程调用均在该类中
    """
    def __init__(self):
        super(Screen, self).__init__()
        """
        初始化函数，内容包括：
        1、初始化显示界面，包括按钮、标签、图片等
        2、创建各子线程类，连接子线程事件触发函数
        3、加载界面样式文件
        4、创建各全局变量
        """

        # 主界面基本参数
        self.resize(1080, 1500)    # 窗口大小
        self.move(0, 390)    # 窗口位置
        self.setWindowTitle('Brushes')    # 窗口标题

        self.LabelSet()    # 设置标签
        # self.ButtonSet()    # 设置按钮

        # 加载界面样式文件
        file = QtCore.QFile("/home/pi/HighTouchTest_34/MyStyle.qss")
        file.open(QtCore.QFile.ReadOnly)
        styleSheet = file.readAll()
        styleSheet = unicode(styleSheet, encoding='utf8')
        QtGui.qApp.setStyleSheet(styleSheet)

        self.showFullScreen()    # 全屏显示

        #创建屏幕触点类
        self.TouchPoint = ScreenPoint(0x1aad, 0x000f)
        # 获取显示器尺寸，pix单位
        screensize = QtGui.QDesktopWidget().screenGeometry()
        # print screensize.width()
        # print screensize.height()
        # 设置显示器尺寸
        self.TouchPoint.pixx = screensize.width()
        self.TouchPoint.pixy = screensize.height()

        # # 创建数据库写入类
        # self.WriteSQL = SQLWrite()

        # 创建获取屏幕触点线程，并将事件触发连接至DrawPoint方法
        self.PointDraw = PointThread(self.TouchPoint)    # 调用获取屏幕触点的线程
        self.PointDraw.Point.connect(self.DrawPoint)    # 将触点信号连接至DrawPoint方法，即有信号发出时，该方法被调用

        # 创建超声波测距子线程，并将事件触发连接至ShowDistance方法
        self.DistanceThread = laser(19200)
        self.DistanceThread.RangeSignal.connect(self.ShowDistance)
        self.Distance = 0

        # 创建RFID刷卡子线程，并将事件触发连接至RFIDAct方法
        self.CardID = RFIDRead()
        self.CardID.IDSignal.connect(self.RFIDAct)

        # 创建延时清除子线程，并将事件触发连接至ClearPointClick方法
        self.ClearPoint = ClearThread()
        self.ClearPoint.ClearPoint.connect(self.ClearPointClick)
        
        # 蓝牙连接类
        self.bluetooth = bluetooth()
        self.bluetooth.Data.connect(self.GetBlueData)
        self.bluetooth.IsConnect.connect(self.BlueConnect)
        self.bluetooth.start()

        # 创建电机子线程，并将事件触发连接至GetPosition方法
        self.MotorPosition = screw()
        self.MotorPosition.FinshSignal.connect(self.GetPosition)

        self.StartButtonClick()

        # 设置全局变量
        self.Score = [0, 0, 0]    # 总成绩
        self.ScoreFlag = [False, False, False]
        self.IDNum = ""    # RFID号
        self.circlesize = 20  # 绘制点的大小
        self.pix = []    # pix坐标
        self.mm = []    # mm坐标
        self.ymm = []    # y坐标值，mm单位

        self.Name = ""
        self.StuNum = ""
        self.Length = 0
        self.Times = 0

    def DrawPoint(self, isdata, ThePoint):
        """
        触摸点绘制函数（手形图片显示函数），由获取屏幕触点子线程发出的事件触发
        isdata为布尔变量，True为有数据，False为无数据
        ThePoint为传递的触点坐标信息，[xpix, ypix, xmm, ymm]
        """
        if isdata == True:
            self.ClearPoint.num = 0
            if ThePoint[0:2] not in self.mm:    # 判断该点是否已经存在
                if ThePoint[2] != 1080 | ThePoint[3] != 0:    # 判断该点是否合法
                    self.pix.append(ThePoint[2:4])
                    self.mm.append(ThePoint[0:2])
                    self.pix.sort(key=lambda x: x[1])    # 以二维数组的第二列排序，从小到大
                    self.HighestPoint = self.pix[0]    # 取最高点，y的pix坐标越小越高
                    self.Hand.move(self.HighestPoint[0] - 260, self.HighestPoint[1])    # 移动手形图片的中指位置至最高点处
                    self.Hand.setVisible(True)    # 显示图片

                    self.update()    # 更新点图形
                    # print ThePoint
                    self.ymm.append(ThePoint[1])
                    Touch = max(self.ymm)
                    self.Score[self.Times] = Touch + self.Distance
                    if self.Times == 0:
                        self.FirstContentLabel.setText(str(self.Score[self.Times])+"mm")
                    elif self.Times == 1:
                        self.SecondContentLabel.setText(str(self.Score[self.Times])+"mm")
                    else:
                        self.ThirdContentLabel.setText(str(self.Score[self.Times])+"mm")

                    self.ScoreContentLabel.setText(str(max(self.Score))+"mm")
        else:
            self.ClearPoint.start()

    def ShowDistance(self, Distance):
        """
        显示并保存超声波测距函数，由超声波测距子线程发出的事件触发
        """
        self.Distance = int(Distance * 10)
        self.DistanceContentLabel.setText(str(self.Distance) + "mm")

        try:
            self.DrawRuler.deleteLater()
        except:
            pass
        self.DrawRuler = ShowRuler(self.Distance, self.TouchPoint.Height, self.TouchPoint.pixy, self)
        self.DrawRuler.move(1000, 0)
        self.DrawRuler.show()
        

    def paintEvent(self, e):
        qp = QtGui.QPainter()
        qp.begin(self)
        self.DrawLine(qp)
        qp.end()

    def DrawLine(self, qp):
        qp.setPen(QtGui.QPen(Qt.red, 2, Qt.SolidLine))
        try:
            lineheight = self.HighestPoint[1]
            qp.drawLine(0, lineheight, 1080, lineheight)
            # qp.drawLine(0, 1800, 1080, 1800)
        except:
            pass

    def RFIDAct(self, IDNum):
        """
        显示并保存RFID卡号函数，由RFID刷卡子线程发出的事件触发
        刷卡后重新测距
        """
        self.IDNum = IDNum
        self.IDContentLabel.setText(IDNum)
        self.DistanceThread.start()

    def closeEvent(self, event):
        """
        重写窗口关闭事件，窗口试图关闭时触发
        显示是否退出对话框
        """
        self.statusBar().showMessage('quiting...')    # 显示一个状态栏
        reply = QtGui.QMessageBox.question(self, 'Message', 'quit?',
                                           QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                                           QtGui.QMessageBox.No)    # 确认对话框
        if reply == QtGui.QMessageBox.Yes:    # 确认退出
            self.PointDraw.StartFlag = False    # 停止线程，run函数检测到标志则退出
            self.TouchPoint.release()    # 释放屏幕占用
            print "程序退出"    # 打印一条信息
            event.accept()    # 响应该退出事件
        else:     # 不确认退出
            self.statusBar().showMessage('')    # 显示一个空状态栏
            event.ignore()    # 不响应该退出事件

    def ButtonSet(self):
        """
        设置按钮
        """
        ClearButton = QtGui.QPushButton("clear", self)  #创建一个清除按钮
        ClearButton.move(10, 10)  #按钮位置
        ClearButton.resize(75, 45)  #按钮大小
        #关联按钮事件触发函数为ClearButtonClick
        self.connect(ClearButton, QtCore.SIGNAL('clicked()'), self.ClearPointClick)

        StartButton = QtGui.QPushButton("Start", self)    #创建一个开始按钮
        StartButton.move(135, 10)    #按钮位置
        StartButton.resize(75, 45)    #按钮大小
        #关联按钮事件触发函数为StartButtonClick
        self.connect(StartButton, QtCore.SIGNAL('clicked()'), self.StartButtonClick)

    def LabelSet(self):
        """
        设置标签，分别为：
        1、显示手形的标签，第一个创建，位于界面底层显示
        2、文字“卡号”的显示标签
        3、卡号具体内容的显示标签
        4、文字“触点”的显示标签
        5、触点具体高度的显示标签
        6、文字“高度”的显示标签
        7、超声波测距高度具体值的显示标签
        8、文字“成绩”的显示标签
        9、成绩具体内容的显示标签
        """
        self.Hand = QLabel(self)
        self.Hand.setObjectName('Hand')
        picture = QtGui.QPixmap('/home/pi/HighTouchTest_34/hand2.png')
        self.Hand.setPixmap(picture)
        self.Hand.move(-100, -100)
        self.Hand.resize(500, 538)    # 将标签设置为图片的大小
        self.Hand.setVisible(False)    # 隐藏该标签

        # 卡号的显示框
        IDLabel = QLabel(self)
        IDLabel.resize(65, 40)
        IDLabel.move(10, 80)
        IDLabel.setText(u"卡号:")

        self.IDContentLabel = QLabel(self)
        self.IDContentLabel.resize(135, 40)
        self.IDContentLabel.move(75, 80)
        self.IDContentLabel.setText("")

        # 姓名的显示框
        NameLabel = QLabel(self)
        NameLabel.resize(65, 40)
        NameLabel.move(10, 145)
        NameLabel.setText(u"姓名:")

        self.NameContentLabel = QLabel(self)
        self.NameContentLabel.resize(135, 40)
        self.NameContentLabel.move(75, 145)
        self.NameContentLabel.setText("")

        # 高度的显示框
        DistanceLabel = QLabel(self)
        DistanceLabel.resize(65, 40)
        DistanceLabel.move(10, 210)
        DistanceLabel.setText(u"高度:")

        self.DistanceContentLabel = QLabel(self)
        self.DistanceContentLabel.resize(135, 40)
        self.DistanceContentLabel.move(75, 210)
        self.DistanceContentLabel.setText("")

        # 第一次成绩的显示框
        FirstLabel = QLabel(self)
        FirstLabel.resize(65, 40)
        FirstLabel.move(10, 275)
        FirstLabel.setText(u"第一次:")

        self.FirstContentLabel = QLabel(self)
        self.FirstContentLabel.resize(135, 40)
        self.FirstContentLabel.move(75, 275)
        self.FirstContentLabel.setText("")

        # 第二次成绩的显示框
        SecondLabel = QLabel(self)
        SecondLabel.resize(65, 40)
        SecondLabel.move(10, 340)
        SecondLabel.setText(u"第二次:")

        self.SecondContentLabel = QLabel(self)
        self.SecondContentLabel.resize(135, 40)
        self.SecondContentLabel.move(75, 340)
        self.SecondContentLabel.setText("")

        # 第三次成绩的显示框
        ThirdLabel = QLabel(self)
        ThirdLabel.resize(65, 40)
        ThirdLabel.move(10, 405)
        ThirdLabel.setText(u"第三次:")

        self.ThirdContentLabel = QLabel(self)
        self.ThirdContentLabel.resize(135, 40)
        self.ThirdContentLabel.move(75, 405)
        self.ThirdContentLabel.setText("")

        # 最终成绩
        ScoreLabel = QLabel(self)
        ScoreLabel.resize(65, 40)
        ScoreLabel.move(10, 470)
        ScoreLabel.setText(u"成绩:")

        self.ScoreContentLabel = QLabel(self)
        self.ScoreContentLabel.resize(135, 40)
        self.ScoreContentLabel.move(75, 470)
        self.ScoreContentLabel.setText("")

    def ClearPointClick(self):
        """"
        响应清除按钮点击事件，点下清除按钮后触发
        """
        if self.ScoreFlag[self.Times] == False and self.Score[self.Times] != 0:
            self.ScoreFlag[self.Times] = True
            try:
                result = "dat::" + self.StuNum + "::" + str(self.Times + 1) + "::" + str(self.Score[self.Times]) + "::dat"
                self.bluetooth.SendData(result)
            except:
                print "send error"

        if self.ScoreFlag[0] and self.ScoreFlag[1] and self.ScoreFlag[2]:
            self.Score = [0, 0, 0]    # 总成绩
            self.ScoreFlag = [False, False, False]
            self.IDNum = ""    # RFID号

            self.Name = ""
            self.StuNum = ""
            self.Length = 0
            self.Times = 0

            self.IDContentLabel.setText("")
            self.NameContentLabel.setText("")
            self.FirstContentLabel.setText("")
            self.SecondContentLabel.setText("")
            self.ThirdContentLabel.setText("")
            self.ScoreContentLabel.setText("")
            
        self.pix = []    # pix坐标
        self.mm = []    # mm坐标
        self.ymm = []    # y坐标值，mm单位
        self.HighestPoint = []
        self.Hand.setVisible(False)
        self.update()

    def StartButtonClick(self):
        """"
        响应开始按钮点击事件，点下清除按钮后触发
        """
        self.TouchPoint.connect()
        self.PointDraw.StartFlag = True
        self.PointDraw.start()    # 开始线程，run方法被调用
        self.DistanceThread.start()
        self.CardID.start()

    def BlueConnect(self):
        pass

    def GetBlueData(self, Name, StuNum, Length, Times):
        self.Name = unicode(Name, 'utf-8') 
        self.StuNum = StuNum
        self.Length = Length
        self.Times = Times - 1
        self.IDContentLabel.setText(StuNum)
        self.NameContentLabel.setText(self.Name)
        print Length
        if Length != 0:
            self.MotorPosition.Length = Length
            self.MotorPosition.start()

    def GetPosition(self):
        self.DistanceThread.start()

    def keyPressEvent(self, e):
        """"
        响应键盘按键事件，检测到esc键按下，产生退出时间
        """
        if e.key() == QtCore.Qt.Key_Escape:
            self.close()

def KeyQuit(signal, frame):
    """
    响应键盘ctrl+c终止程序的命令,强制退出
    """
    ex.TouchPoint.release()
    print "keyboard quit!"
    sys.exit(app.exec_())

signal.signal(signal.SIGINT, KeyQuit)    # 键盘退出事件

app = QtGui.QApplication(sys.argv)    #创建应用
ex = Screen()
ex.show()
sys.exit(app.exec_())
